<?php
/*
 * @Author: KingMin 
 * @Date: 2021-07-13 22:30:48 
 * @Last Modified by:   KingMin 
 * @Last Modified time: 2021-07-13 22:30:48 
 * @The authors website: https://www.kingmin.cn  
 */
/**
 * 登录验证
 * @copyright (c) KINGMIN All Rights Reserved
 */

class LoginAuth{

    const LOGIN_ERROR_USER = -1;
    const LOGIN_ERROR_PASSWD = -2;
    const LOGIN_ERROR_AUTHCODE = -3;
    const LOGIN_ERROR_USER_ISDEL=-4;
    const LOGIN_ERROR_USER_FGL=-5;

    // 获取权限详情
    public static function getroleDetail($key){
        $DB = Database::getInstance();
        $res = $DB->query("SELECT * FROM `".DB_PREFIX."sys_role` where role_key='$key' ");
        $role = array();
        while($row = $DB->fetch_array($res)) {
            $role['role_id'] = htmlspecialchars($row['role_id']);
            $role['role_key'] = htmlspecialchars($row['role_key']);
            $role['data_scope'] = htmlspecialchars($row['data_scope']);
            $role['remark'] = htmlspecialchars($row['remark']);
            $role['role_name'] = htmlspecialchars($row['role_name']);
            $role['order_num'] = htmlspecialchars($row['order_num']);
            $role['status'] = htmlspecialchars($row['status']);
            $role['create_by'] = htmlspecialchars($row['create_by']);
            $role['create_time'] = htmlspecialchars($row['create_time']);
        }
        return $role;
    }
    // 获取用户设备信息
    public static function getMemberDevices($uid){
        $DB = Database::getInstance();
        $res = $DB->query("SELECT * FROM `".DB_PREFIX."sys_member_devices` where `uid`='$uid' AND `isdel`='0' ");
        $devices['list'] = array();
        $text="";
        while($row = $DB->fetch_array($res)) {
            $row['osDt']=json_decode($row['osDt'],true);
            $devices['list'][]=$row;
            $text.=$row['model']." (".$row['system'].") \n\r ";
            
        }
        $devices['text']=$text;
        return $devices;
    }
    // 数据格式
    public static function returnUser($row){
        if($row['gender']==1){
            $gender='男';
        }elseif($row['gender']==2){
            $gender='女';
        }else{
            $gender='保密';
        }
        $role= self::getroleDetail($row['role']);
        $devices=self::getMemberDevices($row['uid']);
        return $user = array(
                    'uname' => htmlspecialchars($row['uname']),
                    'status' => htmlspecialchars($row['status']),
                    'nickName' => htmlspecialchars($row['nickName']),
                    'email' => htmlspecialchars($row['email']),
                    'avatar' => imgUrlpd($row['avatar']?htmlspecialchars($row['avatar']):'/content/images/icon/default.jpg'),
                    'photo' => imgUrlpd($row['avatar']?htmlspecialchars($row['avatar']):'/content/images/icon/default.jpg'),
                    'info' => htmlspecialchars($row['info']),
                    'role' => htmlspecialchars($row['role']),
                    'uid' => htmlspecialchars($row['uid']),
                    'gender' =>$gender,
                    'phone' => htmlspecialchars($row['phone']),
                    'qq' => htmlspecialchars($row['qq']),
                    'remark' => htmlspecialchars($row['remark']),
                    'role_scope' => $role['data_scope'],
                    'role_name' => $role['role_name'],
                    'roles'=> [$role['role_key']],
                    'roless'=> $role,
                    'devices'=> $devices['list'],
                    'device'=> $devices['text'],
                );
    }
    
    /**
     * 账号密码登录
     *
     * @param string $username
     * @param string $password
     * @param string $imgcode
     * @param string $logincode
     */
    public static function checkUser($username, $password,$dt=[],$login=true) {
        if (trim($username) == '' || trim($password) == '') {
            return false;
        } else {
            $bz=rand(10000, 99999);
            $uid="";
            $userData = self::getUserDataByLogin($username);
            if (false === $userData) {
                if($login){
                    self::addUserLoginLog($uid,$username,self::encrypt($password,'E',$bz),2,'账号不正确',$dt,$bz);
                }
                return self::LOGIN_ERROR_USER;
            }
            $uid=$userData['uid'];
            $status=getRequestFormType(false);
            if($status=='admin'){
                if($userData['role']=='ordinary'){
                    if($login){
                        self::addUserLoginLog($uid,$username,self::encrypt($password,'E',$bz),5,'账号不是管理员',$dt,$bz);
                    }
                    return self::LOGIN_ERROR_USER_FGL;
                }
            }
            $hash = $userData['password'];
            if (true === self::checkPassword($password, $hash)){
                $row= $userData;
                if($row['isdel']!='0'){
                    if($login){
                        self::addUserLoginLog($uid,$username,self::encrypt($password,'E',$bz),5,'账号已被删除',$dt,$bz);
                    }
                    return self::LOGIN_ERROR_USER;
                }
                if($row['status']!='0'){
                    if($login){
                        self::addUserLoginLog($uid,$username,self::encrypt($password,'E',$bz),4,'账号被封禁',$dt,$bz);
                    }
                    return self::LOGIN_ERROR_USER_ISDEL;
                }
                $user = self::returnUser($row);
                $string=htmlspecialchars($row['uid']).time().rand(100,999);
                // $user['token']=self::encrypt(json_encode($string),"E","KingMin");
                $user['token']=md5($string);
                if($login){
                    $DB = Database::getInstance();
                    $ipdz=getIp();
                    $logdate=date("Y-m-d H:i:s");
                    $sql=" UPDATE  `".DB_PREFIX."sys_member` SET `login_ip`='$ipdz',`login_date`='$logdate',`login_num`=login_num+1 WHERE `uid`='".$user['uid']."'";
                    $DB->query($sql);
                    self::addUserLoginLog($uid,$username,self::encrypt($password,'E',$bz),1,'账号登录成功',$dt,$user['token'].' ；'.$bz);
                }
                return $user;
            } else{
                if($login){
                    self::addUserLoginLog($uid,$username,$password,3,'密码错误',$dt,$bz);
                }
                return self::LOGIN_ERROR_PASSWD;
            }
            
        }
    }
    /**
    * 添加登录日志
    **/
    /**
    * 添加登录日志
    **/
    public static function addUserLoginLog($uid,$userLogin,$password,$log_status,$msg,$dt=[],$bz="") {
        $DB = Database::getInstance();
        $status=getRequestFormType(false);
        if(!$status){
            $status="";
        }
        $osDt="";
        $log_ip=getIp();
        $location =ipToArea($log_ip);
        if($status!='admin'){
            @$log_os=$dt['log_os'];
            @$log_browser=$dt['log_browser'];
            $osDt=json_encode($dt,JSON_UNESCAPED_UNICODE);
            // $bz= self::addMemberDevice($uid,$dt,"");
            if($uid){
                self::addMemberDevice($uid,$dt,"");
            }
        }else{
            $log_browser=get_broswer();
            $log_os=get_os();
        }
        $sql="INSERT INTO `".DB_PREFIX."sys_log_login`(`status`,`uid`,`user_name`, `user_password`, `log_ip`,`location`, `log_browser`, `log_os`,`osDt`, `log_status`, `log_msg`,`remark`) VALUES('$status','$uid','$userLogin','$password','$log_ip','$location','$log_browser','$log_os','$osDt','$log_status','$msg','$bz')";
        // return $sql;
        $DB->query($sql);
    }
    /**
    /**
    * 添加用户设备
    **/
    public static function addMemberDevice($uid="",$os=[],$bz="") {
        $DB = Database::getInstance();
        $status=getRequestFormType(false);
        if(!$status){
            $status="";
        }
        if(!$uid){
            return false;
        }
        if($status!='admin'){
            $osDt=json_encode($os,JSON_UNESCAPED_UNICODE);
            @$deviceId=$os['deviceId'];
            @$deviceModel=$os['deviceModel'];
            @$deviceOrientation=$os['deviceOrientation'];
            @$model=$os['model'];
            @$system=$os['system'];
            if ($dt = $DB->once_fetch_array("SELECT * FROM `".DB_PREFIX."sys_member_devices` WHERE `uid` = '$uid' AND `deviceId`='$deviceId' AND `isdel`='0'")) {
                $sql="UPDATE `".DB_PREFIX."sys_member_devices` SET `deviceId`='$deviceId'  WHERE `uid`='$uid' AND  `deviceId`='$deviceId'  ;";
            }else{
                $sql="INSERT INTO `".DB_PREFIX."sys_member_devices`(`status`,`uid`,`deviceId`, `deviceModel`, `deviceOrientation`,`model`, `system`,`osDt`, `remark`) VALUES('$status','$uid','$deviceId','$deviceModel','$deviceOrientation','$model','$system','$osDt','$bz');";
            }
            
            $DB->query($sql);
            return true;
        }
        return $status;
    }
    /**
     * 加密与解密 
     * $string 参数
     * $operation E 加密 D 解密
     * $key 动态密文
    */
    public static function encrypt($string,$operation,$key=''){
        $key=$key.'';
        $key_length=strlen($key);   
        $string=$operation=='D'?base64_decode($string):substr(md5($string.$key),0,8).$string;   
        $string_length=strlen($string);   
        $rndkey=$box=array();   
        $result='';   
        for($i=0;$i<=255;$i++){   
               $rndkey[$i]=ord($key[$i%$key_length]);   
            $box[$i]=$i;   
        }   
        for($j=$i=0;$i<256;$i++){   
            $j=($j+$box[$i]+$rndkey[$i])%256;   
            $tmp=$box[$i];   
            $box[$i]=$box[$j];   
            $box[$j]=$tmp;   
        }   
        for($a=$j=$i=0;$i<$string_length;$i++){   
            $a=($a+1)%256;   
            $j=($j+$box[$a])%256;   
            $tmp=$box[$a];   
            $box[$a]=$box[$j];   
            $box[$j]=$tmp;   
            $result.=chr(ord($string[$i])^($box[($box[$a]+$box[$j])%256]));   
        }   
        if($operation=='D'){   
            if(substr($result,0,8)==substr(md5(substr($result,8).$key),0,8)){   
                return substr($result,8);   
            }else{   
                return'';   
            }   
        }else{   
            return str_replace('=','',base64_encode($result));   
        }   
    }   
    /**
     * 登录查询管理员信息
     *
     * @param string $userLogin User's username
     * @return bool|object False on failure, User DB row object
     */
    public static function getUserDataByLogin($userLogin) {
        $DB = Database::getInstance();
        if (empty($userLogin)) {
            return false;
        }
        $isuname="uname";
        if(is_mobile($userLogin)){
            $isuname="phone";
        }
        $userData = false;
        if (!$userData = $DB->once_fetch_array("SELECT * FROM `".DB_PREFIX."sys_member` WHERE `$isuname` = '$userLogin'")) {
            return false;
        }
        $userData['nickName'] = htmlspecialchars($userData['nickName']);
        $userData['uname'] = htmlspecialchars($userData['uname']);
        $userData['uid'] = htmlspecialchars($userData['uid']);
        return $userData;
    }
    /**
     * 通过手机号查询管理员信息
     *
     * @param string $userLogin User's username
     * @return bool|object False on failure, User DB row object
     */
    public static function getPhoneDataByLogin($phoneLogin) {
        $DB = Database::getInstance();
        if (empty($phoneLogin)) {
            return false;
        }
        $userData = false;
        if (!$userData = $DB->once_fetch_array("SELECT * FROM `".DB_PREFIX."sys_member` WHERE `phone` = '$phoneLogin'")) {
            return false;
        }
        $userData['nickName'] = htmlspecialchars($userData['nickName']);
        $userData['uname'] = htmlspecialchars($userData['uname']);
        $userData['uid'] = htmlspecialchars($userData['uid']);
        return $userData;
    }
    
    public static function getLoginDetail($uid) {
        $DB = Database::getInstance();
        if (empty($uid)) {
            return false;
        }
        $userData = false;
        if (!$userData = $DB->once_fetch_array("SELECT * FROM `".DB_PREFIX."sys_member` WHERE `uid` = '$uid'")) {
            return false;
        }
        $userData = self::returnUser($userData);
        return $userData;
    }
    
    // 获取管理员列表
     // 获取用户列表
    public static function getAdminList($pages=[],$dt=[],$uname=""){
        $DB=Database::getInstance();
        @$isAll=$pages['isAll'];
        $output = [
			'pages'=>[
			    'isAll'=>$isAll?true:false,
    			'recordCount' => 0,     //满足条件的总记录数
    		    'pageSize' => 10,        //每页大小，即每页最多可以显示的记录数量
    		    'pageCount' => 0,       //总页数
    		    'pno' => 1,          //当前数据所在页号
			 ],
			'list' => [] ,         //当前页中的数据
	    ];
	    $bySql="ORDER BY `uid` DESC ";
	    $isfym="";$wSql="";
	    if(@$pages['pno']){
		  $output['pages']['pno'] = intval($pages['pno']);
		}
		if(@$pages['pageSize']){
		  $output['pages']['pageSize']= intval($pages['pageSize']);
		}
	    $pno = $output['pages']['pno'];$pgs =$output['pages']['pageSize'];
	    if(@$dt['name']&&@$dt['key']){
	        if($dt['name']=='uid'){
	            $wSql.=" AND ( `".$dt['name']."` = '".$dt['key']."' ) ";
	        }elseif($dt['name']=='uname'){
	            $wSql.=" AND ( `uname` LIKE '%".$dt['key']."%' OR `nickName` LIKE '%".$dt['key']."%' ) ";
	        }else{
	            $wSql.=" AND ( `".$dt['name']."` LIKE '%".$dt['key']."%' ) ";
	        }
	    }
	    if(@$dt['status']||@$dt['status']=='0'){
	        $wSql.=" AND `status`='".$dt['status']."' ";
	    }
	    if(@$dt['role']){
	        $wSql.=" AND `role`='".$dt['role']."' ";
	    }
	    if(@$dt['gender']||@$dt['gender']=='0'){
	        $wSql.=" AND `gender`='".$dt['gender']."' ";
	    }
	    if(@$dt['loginIp']){
	        $wSql.=" AND `login_ip`='".$dt['loginIp']."' ";
	    }
	    if(@$dt['orderBy']['order']){
	        if(strtolower($dt['orderBy']['order'])=='ascending'){
	            if(@$dt['orderBy']['prop']){
	               $bySql="ORDER BY `".$dt['orderBy']['prop']."` ASC "; 
	            }
	            
	        }
	        if(strtolower($dt['orderBy']['order'])=='descending'){
	            if(@$dt['orderBy']['prop']){
	               $bySql="ORDER BY `".$dt['orderBy']['prop']."` DESC "; 
	            }
	            
	        }
	    }
	    if($uname!='kingmin'){
	        $wSql.=" AND `uname`!='kingmin' ";
	    }
	    $totalSql = " SELECT COUNT(*) as total  FROM `" . DB_PREFIX . "sys_member` WHERE `isdel`='0' AND `role`!='ordinary'  $wSql ;";
		$res = $DB->fetch_array($DB->query($totalSql));
		$output['pages']['recordCount'] = intval($res['total']);
		//计算总页数
		$output['pages']['pageCount'] = ceil($output['pages']['recordCount']/$output['pages']['pageSize']);
		//获取指定页中的数据
		$start = ($output['pages']['pno']-1)*$output['pages']['pageSize'];
		$count = $output['pages']['pageSize'];
		if(!$output['pages']['isAll']){
			$isfym="LIMIT $start,$count";
	    }
	    
	    $sql = "SELECT * FROM `" . DB_PREFIX . "sys_member` WHERE `isdel`='0' AND `role`!='ordinary' $wSql $bySql  $isfym;";
        $logs = $DB->query($sql);
        // $output['sql']=$sql;
        $data = array();
        foreach ($logs as $key => $v) {
            $user=User_Model::memberJson($v);
            $role= self::getroleDetail($v['role']);
            $user['roleName']=$role['role_name'];
            $user['roles']= $role;
            $data[]=$user;
        }
        $output['list']=$data;
        return $output;
    }
    
    
    /**
     * 将明文密码和数据库加密后的密码进行验证
     *
     * @param string $password Plaintext user's password
     * @param string $hash Hash of the user's password to check against.
     * @return bool False, if the $password does not match the hashed password
     */
    public static function checkPassword($password, $hash) {
        global $em_hasher;
        if (empty($em_hasher)) {
            $em_hasher = new PasswordHash(8, true);
        }
        $check = $em_hasher->CheckPassword($password, $hash);
        return $check;
    }

    /**
     * 写用于登录验证cookie
     *
     * @param int $user_id User ID
     * @param bool $remember Whether to remember the user or not
     */
    public static function setAuthCookie($user_login, $ispersis = false) {
        if ($ispersis) {
            $expiration  = time() + 3600 * 24 * 30 * 12;
        } else {
            $expiration = null;
        }
        $auth_cookie_name = AUTH_COOKIE_NAME;
        $auth_cookie = self::generateAuthCookie($user_login, $expiration);
        setcookie($auth_cookie_name, $auth_cookie, $expiration,'/');
    }

    /**
     * 生成登录验证cookie
     *
     * @param int $user_id user login
     * @param int $expiration Cookie expiration in seconds
     * @return string Authentication cookie contents
     */
    private static function generateAuthCookie($user_login, $expiration) {
        $key = self::emHash($user_login . '|' . $expiration);
        $hash = hash_hmac('md5', $user_login . '|' . $expiration, $key);

        $cookie = $user_login . '|' . $expiration . '|' . $hash;

        return $cookie;
    }

    /**
     * Get hash of given string.
     *
     * @param string $data Plain text to hash
     * @return string Hash of $data
     */
    private static function emHash($data) {
        $key = AUTH_KEY;
        return hash_hmac('md5', $data, $key);
    }

    /**
     * 验证cookie
     * Validates authentication cookie.
     *
     * @param string $cookie Optional. If used, will validate contents instead of cookie's
     * @return bool|int False if invalid cookie, User ID if valid.
     */
    private static function validateAuthCookie($cookie = '') {
        if (empty($cookie)) {
            return false;
        }

        $cookie_elements = explode('|', $cookie);
        if (count($cookie_elements) != 3) {
            return false;
        }

        list($username, $expiration, $hmac) = $cookie_elements;

        if (!empty($expiration) && $expiration < time()) {
            return false;
        }

        $key = self::emHash($username . '|' . $expiration);
        $hash = hash_hmac('md5', $username . '|' . $expiration, $key);

        if ($hmac != $hash) {
            return false;
        }

        $user = self::getUserDataByLogin($username);
        if (!$user) {
            return false;
        }
        return $user;
    }

    /**
     * 生成token，防御CSRF攻击
     */
    public static function genToken() {
        $token_cookie_name = 'EM_TOKENCOOKIE_' . md5(substr(AUTH_KEY, 16, 32) . UID);
        if (isset($_COOKIE[$token_cookie_name])) {
            return $_COOKIE[$token_cookie_name];
        } else {
            $token = md5(getRandStr(16));
            setcookie($token_cookie_name, $token, 0, '/');
            return $token;
        }
    }

    /**
     * 检查token，防御CSRF攻击
     */
    public static function checkToken(){
        $token = isset($_REQUEST['token']) ? addslashes($_REQUEST['token']) : '';
        if ($token != self::genToken()) {
            emMsg('权限不足，token error');
        }
    }
}
